package com.twj.tools.poi;


import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.List;

import static com.twj.tools.img.ImageUtil.convertBase64StrToImage;
import static com.twj.tools.img.ImageUtil.convertImageToBase64Str;


/**
 * https://poi.apache.org/index.html
 * https://blog.51cto.com/u_15064628/4338977
 */
public class WordPoiTest {

    public static void main(String[] args) throws Exception {

        XWPFDocument xwpfDocument = generateWordXWPFDocument();
        xwpfDocument.write(new FileOutputStream("D:\\test\\99.docx"));
//        formatDoc();
        System.out.println("word  finish!!");
    }

    /**
     * word整体样式
     */
    private static CTStyles wordStyles = null;

    /**
     * Word整体样式
     */
    static {
        XWPFDocument template;
        try {
            // 读取模板文档
            template = new XWPFDocument(new FileInputStream("D:\\test\\template.docx"));
            // 获得模板文档的整体样式
            wordStyles = template.getStyle();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XmlException e) {
            e.printStackTrace();
        }
    }

    public static void formatDoc() throws IOException {
        // 新建的word文档对象
        XWPFDocument doc = new XWPFDocument();
        // 获取新建文档对象的样式
        XWPFStyles newStyles = doc.createStyles();
        // 关键行// 修改设置文档样式为静态块中读取到的样式
        newStyles.setStyles(wordStyles);

        

        // 开始内容输入
        // 标题1，1级大纲
        XWPFParagraph para1 = doc.createParagraph();
        // 关键行// 1级大纲
        para1.setStyle("1");
        XWPFRun run1 = para1.createRun();
        // 标题内容
        run1.setText("标题 1");

        // 标题2
        XWPFParagraph para2 = doc.createParagraph();
        // 关键行// 2级大纲
        para2.setStyle("3");
        XWPFRun run2 = para2.createRun();
        // 标题内容
        run2.setText("标题 2");

        // 正文
        XWPFParagraph paraX = doc.createParagraph();
        XWPFRun runX = paraX.createRun();
        // 正文内容
        runX.setText("正文");

        // word写入到文件
        FileOutputStream fos = new FileOutputStream("D:\\test\\bb.docx");
        doc.write(fos);
        fos.close();
    }


    /**
     * @return
     */
    public static XWPFDocument generateWordXWPFDocument() {
        //1.构建文档对象
        XWPFDocument doc = new XWPFDocument();
        // 获取新建文档对象的样式
//        XWPFStyles newStyles = doc.createStyles();
//        // 修改设置文档样式为静态块中读取到的样式
//        newStyles.setStyles(wordStyles);

        doc.createStyles().setStyles(wordStyles);

        // 标题
        XWPFParagraph para = doc.createParagraph();
        para.setStyle("4");//一级标题
        para.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun xwpfRun = para.createRun();
        xwpfRun.setBold(true);
        xwpfRun.setFontFamily("宋体");
//        xwpfRun.setFontFamily("方正小标宋简体");
        xwpfRun.setText("主题一：二八定律");
        xwpfRun.setFontSize(18);

        // 段落
        createChapter(doc, "4", "--从税收数据分布，“抓住”其关键少数", 14);
        createParagraph(doc, "著名的经济学家帕累托提出的“二八定律”指出80%的财富是由20%的人创造的。在中国，19个城市群承载了全国3/4以上人口，贡献了八成以上GDP；与之类似，全球共223个国家与地区，其中20国集团GDP总量占全球85%，贸易占全球贸易总额的80%以上，人口占全球人口的2/3。“关键少数”对指导开展管理活动非常有帮助。");
        createParagraph(doc, "基于“五个一”归集数据，我们发现对于国家税收来说，同样也有许多情况符合二八定理。比如，大量的税收收入来自于数量较少的大企业、大量的个税收入也是来源于少数的高收入人群等。");

        // Chapter 2
        createChapter(doc, "4", "现象一：【X%】的【维度/标签】贡献了【Y%】的【指标】", 16);

        createParagraph(doc, "全国【YYYY】年【X%】【维度/标签】贡献了【Y%】【指标】，主要集中在【省份】、【行业】，呈现了一定的聚集性。");
        createParagraph(doc, "1.【YYYY】年，全国【指标】合计值为【XXX】【单位】，其中【X%】的【维度/标签】贡献了【指标】合计值为【XXX】【单位】，占全国【指标】合计值【百分比%】，【指标】贡献排名前三的省份分别为【XX省】、【XX省】和【XX省】，分别占全国总量的【百分比%】、【百分比%】和【百分比%】，（详见表X.1）。");


        createChapter(doc, "4", "图片展示", 16);
        // 图片
//        InputStream stream = null;
//        String data = "";
        String data = "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";
        ;
        String fileName = "D:\\test\\pic\\img3.png";
        //模拟base64解析
        data = convertImageToBase64Str(fileName);

        //            XWPFParagraph pargh = doc.createParagraph();

        File file = convertBase64StrToImage(data, fileName);

//            XWPFRun run = pargh.createRun();
//            run.addPicture(stream, Document.PICTURE_TYPE_PNG, "Generated", Units.toEMU(400), Units.toEMU(400));

//            CTInline inline = run.getCTR().addNewDrawing().addNewInline();
//            insertPicture(doc, file.getAbsolutePath(), inline,  500, 310);


        addPicture(doc, file);
        //添加图片时，如果剩余高度小于图片高度 需要分页（剩余高度？）
        //doc.createParagraph().createRun().addBreak(BreakType.PAGE);

        createChapter(doc, "4", "图片二展示", 16);
        addPicture(doc, file);
//        createPicture(doc,file.getAbsolutePath(),500,300);

        doc.createParagraph().createRun().addBreak(BreakType.PAGE);
        createChapter(doc, "4", "附件表格展示", 16);
        createTable(doc);
        return doc;
    }

    /**
     * @param doc
     * @param file 图片
     * @description 添加圖片，文字环绕型
     * @time 创建时间：2023/7/4 15:04
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    private static void addPicture(XWPFDocument doc, File file) {

        System.out.println("file = " + file.getAbsolutePath());
        XWPFRun run = doc.createParagraph().createRun();
        InputStream in;
        //计算适合文档宽高的图片EMU数值
        BufferedImage read = null;
        int picWidth = 300, picHeight = 200;
        try {
            read = ImageIO.read(file);
            int width = read.getWidth();
            int height = read.getHeight();
            //下面按照图片的实际大小进行同比例缩放
            picWidth = 300;
            picHeight = picWidth * height / width;

            System.out.println("----width-->" + width + "--pic-width->" + picWidth + "- toEMU->" + Units.toEMU(picWidth));
            System.out.println("----height-->" + height + "--pic-height->" + picHeight + "- toEMU->" + Units.toEMU(picHeight));
            in = new FileInputStream(file);
            run.addPicture(in, Document.PICTURE_TYPE_PNG, file.getName(), Units.toEMU(picWidth), Units.toEMU(picHeight));
            in.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }


        // 2. 获取到图片数据
        CTDrawing drawing = run.getCTR().getDrawingArray(0);
        CTGraphicalObject graphicalobject = drawing.getInlineArray(0).getGraphic();

        //拿到新插入的图片替换添加CTAnchor 设置浮动属性 删除inline属性
        CTAnchor anchor = getAnchorWithGraphic(graphicalobject, "TEST1",
                Units.toEMU(picWidth), Units.toEMU(picHeight),//图片大小
                Units.toEMU(0), Units.toEMU(0), false);//相对当前段落位置 需要计算段落已有内容的左偏移
        drawing.setAnchorArray(new CTAnchor[]{anchor});//添加浮动属性
        drawing.removeInline(0);//删除行内属性
        addPicHolderParagraph(doc, picHeight);
    }


    /**
     * @param doc
     * @param height 高度
     * @description 添加图片占位段落，否则图片会叠加
     * @time 创建时间：2023/7/4 15:00
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    private static void addPicHolderParagraph(XWPFDocument doc, int height) {

        int count = height / 28;
        System.out.println("count = " + count);
        for (int i = 0; i < count; i++) {
            doc.createParagraph();
        }
        doc.createParagraph().createRun().setText("wewwewew");
    }

    /**
     * @param ctGraphicalObject 图片数据
     * @param deskFileName      图片描述
     * @param width             宽
     * @param height            高
     * @param leftOffset        水平偏移 left
     * @param topOffset         垂直偏移 top
     * @param behind            文字上方，文字下方
     * @return
     * @description 图片xml 文字环绕型非内嵌
     * @time 创建时间：2023/7/4 14:58
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static CTAnchor getAnchorWithGraphic(CTGraphicalObject ctGraphicalObject,
                                                String deskFileName, int width, int height,
                                                int leftOffset, int topOffset, boolean behind) {

        String anchorXML =
                "<wp:anchor xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" "
                        + "simplePos=\"0\" relativeHeight=\"0\" behindDoc=\"" + ((behind) ? 1 : 0) + "\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">"
                        + "<wp:simplePos x=\"0\" y=\"0\"/>"
                        + "<wp:positionH relativeFrom=\"column\">"
                        + "<wp:posOffset>" + leftOffset + "</wp:posOffset>"
                        + "</wp:positionH>"
                        + "<wp:positionV relativeFrom=\"paragraph\">"
                        + "<wp:posOffset>" + topOffset + "</wp:posOffset>" +
                        "</wp:positionV>"
                        + "<wp:extent cx=\"" + width + "\" cy=\"" + height + "\"/>"
                        + "<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>"
                        + "<wp:wrapNone/>"
                        + "<wp:docPr id=\"1\" name=\"Drawing 0\" descr=\"" + deskFileName + "\"/><wp:cNvGraphicFramePr/>"
                        + "</wp:anchor>";

        CTDrawing drawing = null;
        try {
            drawing = CTDrawing.Factory.parse(anchorXML);
        } catch (XmlException e) {
            e.printStackTrace();
        }
        CTAnchor anchor = drawing.getAnchorArray(0);
        anchor.setGraphic(ctGraphicalObject);
        return anchor;
    }


    private static void createTable(XWPFDocument doc) {
        // 表格
        XWPFParagraph paragraph = doc.createParagraph();
        //创建table 表格 5行 5 列
        XWPFTable table = paragraph.getDocument().createTable(5, 5);
        //设置宽度
        table.setWidth(500);
        //设置每行 内外边距
        table.setCellMargins(40, 40, 40, 40);

        // 表格属性
        CTTblPr tablePr = table.getCTTbl().addNewTblPr();
        // 表格宽度
        CTTblWidth width = tablePr.addNewTblW();
        width.setW(BigInteger.valueOf(8000));

        //设置标题
        List<XWPFTableCell> tableCells = table.getRow(0).getTableCells();
        tableCells.get(0).setText("标题一");
        tableCells.get(1).setText("标题二");
        tableCells.get(2).setText("标题三");
        tableCells.get(3).setText("标题四");
        tableCells.get(4).setText("标题五");

        //填充数据
        for (int i = 1; i < 5; i++) {
            tableCells = table.getRow(i).getTableCells();
            for (int j = 0; j < 5; j++) {
                tableCells.get(j).setText("a" + j);
            }
        }
    }

    /**
     * @param doc
     * @param style    样式
     * @param content  内容
     * @param fontSize 字体大小
     * @description 添加章节
     * @time 创建时间：2023/7/4 15:02
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static void createChapter(XWPFDocument doc, String style, String content, Integer fontSize) {

        XWPFParagraph paragraph = doc.createParagraph();
        paragraph.setStyle(style);//一级标题

        //设置位置 居中 左 右
        paragraph.setAlignment(ParagraphAlignment.LEFT);
        XWPFRun xwpfRun = paragraph.createRun();
        //加粗
        xwpfRun.setBold(true);
        //文本
        xwpfRun.setText(content);
        //字体大小
        xwpfRun.setFontSize(fontSize);
//        xwpfRun.setFontFamily("楷体_GB2312");
    }

    /**
     * @param doc
     * @param content 内容
     * @description 添加段落
     * @time 创建时间：2023/7/4 15:02
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static void createParagraph(XWPFDocument doc, String content) {
        XWPFParagraph xwpfParagraph = doc.createParagraph();
        XWPFRun xwpfRun = xwpfParagraph.createRun();
        xwpfRun.setText(content);
        xwpfRun.setFontSize(16);
    }

    /**
     * insert Picture
     *
     * @param document
     * @param filePath
     * @param inline
     * @param width
     * @param height
     * @throws InvalidFormatException
     * @throws FileNotFoundException
     */
    private static void insertPicture(XWPFDocument document, String filePath, CTInline inline, int width, int height) throws InvalidFormatException, FileNotFoundException {
        document.addPictureData(new FileInputStream(filePath), XWPFDocument.PICTURE_TYPE_PNG);
        int id = document.getAllPictures().size() - 1;
        final int EMU = 9525;
        width *= EMU;
        height *= EMU;
        String blipId = document.getAllPictures().get(id).getPackageRelationship().getId();
        String picXml = getPicXml(blipId, width, height);
        XmlToken xmlToken = null;
        try {
            xmlToken = XmlToken.Factory.parse(picXml);
        } catch (XmlException xe) {
            xe.printStackTrace();
        }
//        CTGraphicalObjectData graphicData = inline.addNewGraphic().addNewGraphicData();
//        graphicData.set(xmlToken);

        inline.set(xmlToken);
        inline.setDistT(width);
        inline.setDistB(0);
        inline.setDistL(0);
        inline.setDistR(0);


        CTPositiveSize2D extent = inline.addNewExtent();
        extent.setCx(width);
        extent.setCy(height);

        CTNonVisualDrawingProps docPr = inline.addNewDocPr();
        docPr.setId(id);
        docPr.setName("IMG_" + id);
        docPr.setDescr("IMG_" + id);

    }

    private static void insertPicture2(XWPFDocument document, String filePath, CTInline inline, CTAnchor ctAnchor, int width, int height) throws InvalidFormatException, FileNotFoundException {
        document.addPictureData(new FileInputStream(filePath), XWPFDocument.PICTURE_TYPE_PNG);
        int id = document.getAllPictures().size() - 1;
        final int EMU = 9525;
        width *= EMU;
        height *= EMU;
        String blipId = document.getAllPictures().get(id).getPackageRelationship().getId();
        String picXml = getPicXml2(blipId, width, height);
        XmlToken xmlToken = null;
        try {
            xmlToken = XmlToken.Factory.parse(picXml);
        } catch (XmlException xe) {
            xe.printStackTrace();
        }
        ctAnchor.set(xmlToken);
        ctAnchor.setDistT(0);
        ctAnchor.setDistB(0);
        ctAnchor.setDistL(0);
        ctAnchor.setDistR(0);

        CTPositiveSize2D extent = ctAnchor.addNewExtent();
        extent.setCx(width);
        extent.setCy(height);
        CTNonVisualDrawingProps docPr = ctAnchor.addNewDocPr();
        docPr.setId(id);
        docPr.setName("IMG_" + id);
        docPr.setDescr("IMG_" + id);
    }

    private static String getPicXml2(String relationId, int width, int height) {

        String xml = "<wp:anchor allowOverlap=\"0\" layoutInCell=\"1\" locked=\"0\" behindDoc=\"0\" relativeHeight=\"0\" simplePos=\"0\" distR=\"0\" distL=\"0\" distB=\"0\" distT=\"0\" " +

                " xmlns:wp=\"[http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing](http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing)\"" +

                " xmlns:wp14=\"[http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing](http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing)\"" +

                " xmlns:r=\"[http://schemas.openxmlformats.org/officeDocument/2006/relationships](http://schemas.openxmlformats.org/officeDocument/2006/relationships)\" >" +

                "<wp:simplePos y=\"0\" x=\"0\"/>" +

                "<wp:positionH relativeFrom=\"column\">" +

                "<wp:align>center</wp:align>" +

                "</wp:positionH>" +

                "<wp:positionV relativeFrom=\"paragraph\">" +

                "<wp:posOffset>0</wp:posOffset>" +

                "</wp:positionV>" +

                "<wp:extent cy=\"" + height + "\" cx=\"" + width + "\"/>" +

                "<wp:effectExtent b=\"0\" r=\"0\" t=\"0\" l=\"0\"/>" +

                "<wp:wrapTopAndBottom/>" +

                "<wp:docPr descr=\"Picture Alt\" name=\"Picture Hit\" id=\"0\"/>" +

                "<wp:cNvGraphicFramePr>" +

                "<a:graphicFrameLocks noChangeAspect=\"true\" xmlns:a=\"[http://schemas.openxmlformats.org/drawingml/2006/main](http://schemas.openxmlformats.org/drawingml/2006/main)\" />" +

                "</wp:cNvGraphicFramePr>" +

                "<a:graphic xmlns:a=\"[http://schemas.openxmlformats.org/drawingml/2006/main](http://schemas.openxmlformats.org/drawingml/2006/main)\">" +

                "<a:graphicData uri=\"[http://schemas.openxmlformats.org/drawingml/2006/picture](http://schemas.openxmlformats.org/drawingml/2006/picture)\" xmlns:a=\"[http://schemas.openxmlformats.org/drawingml/2006/main](http://schemas.openxmlformats.org/drawingml/2006/main)\">" +

                "<pic:pic xmlns:pic=\"[http://schemas.openxmlformats.org/drawingml/2006/picture](http://schemas.openxmlformats.org/drawingml/2006/picture)\">" +

                "<pic:nvPicPr>" +

                "<pic:cNvPr name=\"Picture Hit\" id=\"1\"/>" +

                "<pic:cNvPicPr/>" +

                "</pic:nvPicPr>" +

                "<pic:blipFill>" +

                "<a:blip r:embed=\"" + relationId + "\"/>" +

                "<a:stretch>" +

                "<a:fillRect/>" +

                "</a:stretch>" +

                "</pic:blipFill>" +

                "<pic:spPr>" +

                "<a:xfrm>" +

                "<a:off y=\"0\" x=\"0\"/>" +

                "<a:ext cy=\"" + height + "\" cx=\"" + width + "\"/>" +

                "</a:xfrm>" +

                "<a:prstGeom prst=\"rect\">" +

                "<a:avLst/>" +

                "</a:prstGeom>" +

                "</pic:spPr>" +

                "</pic:pic>" +

                "</a:graphicData>" +

                "</a:graphic>" +

                "<wp14:sizeRelH relativeFrom=\"margin\">" +

                "<wp14:pctWidth>0</wp14:pctWidth>" +

                "</wp14:sizeRelH>" +

                "<wp14:sizeRelV relativeFrom=\"margin\">" +

                "<wp14:pctHeight>0</wp14:pctHeight>" +

                "</wp14:sizeRelV>" +

                "</wp:anchor>";
        return xml;
    }

    /**
     * get the xml of the picture
     *
     * @param blipId
     * @param width
     * @param height
     * @return
     */
    private static String getPicXml(String blipId, int width, int height) {
        String picXml = "" + "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" + "   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" + "      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" + "         <pic:nvPicPr>" + "            <pic:cNvPr id=\"" + 0 + "\" name=\"Generated\"/>" + "            <pic:cNvPicPr/>" + "         </pic:nvPicPr>" + "         <pic:blipFill>" + "            <a:blip r:embed=\"" + blipId + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" + "            <a:stretch>" + "               <a:fillRect/>" + "            </a:stretch>" + "         </pic:blipFill>" + "         <pic:spPr>" + "            <a:xfrm>" + "               <a:off x=\"0\" y=\"0\"/>" + "               <a:ext cx=\"" + width + "\" cy=\"" + height + "\"/>" + "            </a:xfrm>" + "            <a:prstGeom prst=\"rect\">" + "               <a:avLst/>" + "            </a:prstGeom>" + "         </pic:spPr>" + "      </pic:pic>" + "   </a:graphicData>" + "</a:graphic>";
        return picXml;
    }

    /**
     * 批量插入多张图片，一张一行
     * urls是以“,”为分隔的多张图片拼接的字符串
     */
    public static void setCellImg(XWPFTableCell cell, String urls) throws Exception {
        try {
            String[] url = urls.split(",");
            //获取单元格的段落
            XWPFParagraph paragraphs = cell.getParagraphs().get(0);
            XWPFRun run = paragraphs.getRuns().isEmpty() ? paragraphs.createRun() : paragraphs.getRuns().get(0);
            int index = 0;
            for (String path : url) {
                File image = new File(path);
                //判断图片是否存在
                if (!image.exists()) {
                    continue;
                }
                //判断图片的格式
                int format = 0;
                if (path.endsWith(".emf")) {
                    format = XWPFDocument.PICTURE_TYPE_EMF;
                } else if (path.endsWith(".wmf")) {
                    format = XWPFDocument.PICTURE_TYPE_WMF;
                } else if (path.endsWith(".pict")) {
                    format = XWPFDocument.PICTURE_TYPE_PICT;
                } else if (path.endsWith(".jpeg") || path.endsWith(".jpg")) {
                    format = XWPFDocument.PICTURE_TYPE_JPEG;
                } else if (path.endsWith(".png")) {
                    format = XWPFDocument.PICTURE_TYPE_PNG;
                } else if (path.endsWith(".dib")) {
                    format = XWPFDocument.PICTURE_TYPE_DIB;
                } else if (path.endsWith(".gif")) {
                    format = XWPFDocument.PICTURE_TYPE_GIF;
                } else if (path.endsWith(".tiff")) {
                    format = XWPFDocument.PICTURE_TYPE_TIFF;
                } else if (path.endsWith(".eps")) {
                    format = XWPFDocument.PICTURE_TYPE_EPS;
                } else if (path.endsWith(".bmp")) {
                    format = XWPFDocument.PICTURE_TYPE_BMP;
                } else if (path.endsWith(".wpg")) {
                    format = XWPFDocument.PICTURE_TYPE_WPG;
                } else {
                    continue;
                }

                //获取图片文件流
                FileInputStream is = new FileInputStream(path);
                //计算适合文档宽高的图片EMU数值
                BufferedImage read = ImageIO.read(image);
                int width = Units.toEMU(read.getWidth());
                int height = Units.toEMU(read.getHeight());
                //1 EMU = 1/914400英寸= 1/36000 mm,15是word文档中图片能设置的最大宽度cm
                if (width / 360000 > 15) {
                    NumberFormat f = NumberFormat.getNumberInstance();
                    f.setMaximumFractionDigits(0);
                    f.setRoundingMode(RoundingMode.UP);
                    Double d = width / 360000 / 15d;
                    width = Integer.valueOf(f.format(width / d).replace(",", ""));
                    height = Integer.valueOf(f.format(height / d).replace(",", ""));
                }
                run.addPicture(is, format, image.getName(), width, height);
                is.close();
                if (index != url.length - 1) {
                    run.addBreak();//换行
                }
                index++;
            }
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 批量插入多张图片，一张一行
     * urls是以“,”为分隔的多张图片拼接的字符串
     */
    public static void setCellImg(XWPFParagraph paragraphs, String urls) throws Exception {
        try {
            String[] url = urls.split(",");
            //获取单元格的段落
//            XWPFParagraph paragraphs = cell.getParagraphs().get(0);
            XWPFRun run = paragraphs.getRuns().isEmpty() ? paragraphs.createRun() : paragraphs.getRuns().get(0);
            int index = 0;
            for (String path : url) {
                File image = new File(path);
                //判断图片是否存在
                if (!image.exists()) {
                    continue;
                }
                //判断图片的格式
                int format = 0;
                if (path.endsWith(".emf")) {
                    format = XWPFDocument.PICTURE_TYPE_EMF;
                } else if (path.endsWith(".wmf")) {
                    format = XWPFDocument.PICTURE_TYPE_WMF;
                } else if (path.endsWith(".pict")) {
                    format = XWPFDocument.PICTURE_TYPE_PICT;
                } else if (path.endsWith(".jpeg") || path.endsWith(".jpg")) {
                    format = XWPFDocument.PICTURE_TYPE_JPEG;
                } else if (path.endsWith(".png")) {
                    format = XWPFDocument.PICTURE_TYPE_PNG;
                } else if (path.endsWith(".dib")) {
                    format = XWPFDocument.PICTURE_TYPE_DIB;
                } else if (path.endsWith(".gif")) {
                    format = XWPFDocument.PICTURE_TYPE_GIF;
                } else if (path.endsWith(".tiff")) {
                    format = XWPFDocument.PICTURE_TYPE_TIFF;
                } else if (path.endsWith(".eps")) {
                    format = XWPFDocument.PICTURE_TYPE_EPS;
                } else if (path.endsWith(".bmp")) {
                    format = XWPFDocument.PICTURE_TYPE_BMP;
                } else if (path.endsWith(".wpg")) {
                    format = XWPFDocument.PICTURE_TYPE_WPG;
                } else {
                    continue;
                }

                //获取图片文件流
                FileInputStream is = new FileInputStream(image);
                //计算适合文档宽高的图片EMU数值
                BufferedImage read = ImageIO.read(image);
                int width = Units.toEMU(read.getWidth());
                int height = Units.toEMU(read.getHeight());
                //1 EMU = 1/914400英寸= 1/36000 mm,15是word文档中图片能设置的最大宽度cm
                /*if(width/360000>15){
                    NumberFormat f = NumberFormat.getNumberInstance();
                    f.setMaximumFractionDigits(0);
                    f.setRoundingMode(RoundingMode.UP);
                    Double d=width/360000/15d;
                    width = Integer.valueOf(f.format(width/d).replace(",",""));
                    height = Integer.valueOf(f.format(height/d).replace(",",""));
                }*/

                run.addPicture(is, format, image.getName(), width, height);

//                renderPicture(run,is,width,height);
                is.close();


                if (index != url.length - 1) {
                    run.addBreak();//换行
                }
                index++;
            }
        } catch (Exception e) {
            throw e;
        }
    }

    /**
     * 设置页边距
     *
     * @param document doc对象
     * @param left     左边距
     * @param right    右边距
     * @param top      上边距
     * @param bottom   下边距
     */
    public static void setPageMargin(XWPFDocument document,
                                     long left,
                                     long right,
                                     long top,
                                     long bottom) {
        CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();
        CTPageMar pageMar = sectPr.addNewPgMar();
        pageMar.setLeft(BigInteger.valueOf(left));
        pageMar.setRight(BigInteger.valueOf(right));
        pageMar.setTop(BigInteger.valueOf(top));
        pageMar.setBottom(BigInteger.valueOf(bottom));
    }

}